<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Expire" content="0"/>
  <title>select_test.html</title>
  <script type="text/javascript" src="test_bootstrap.js"></script>
  <script type="text/javascript" src="jquery.min.js"></script>
  <script type="text/javascript">
    goog.require('bot.action');
    goog.require('bot.locators');
    goog.require('bot.userAgent');
    goog.require('goog.array');
    goog.require('goog.dom');
    goog.require('goog.events');
    goog.require('goog.testing.jsunit');
    goog.require('goog.userAgent');
  </script>
  <script type="text/javascript">
    var singleSelect, multiSelect, radioButtons, checkboxes, changeCount;

    function setUpPage() {
      singleSelect = bot.locators.findElement({id: 'singleSelect'});
      multiSelect = bot.locators.findElement({id: 'multiSelect'});
      checkboxes = bot.locators.findElements({name: 'checkbox'});
      radioButtons = bot.locators.findElements({name: 'radio'});
    }

    function setUp() {
      goog.events.removeAll();
      singleSelect.selectedIndex = 0;
      goog.array.forEach(multiSelect.options, function(e) {
        e.selected = false;
      });
      goog.array.forEach(checkboxes, function(e) {
        e.checked = false;
      });
      goog.array.forEach(radioButtons, function(e) {
        e.checked = false;
      });
    }

    function checkActionCompatibility(action) {
      if (action == bot.action.tap) {
        return bot.events.SUPPORTS_TOUCH_EVENTS;
      }
      return true;
    }

    function expectChanges(target) {
      changeCount = 0;
      goog.events.listen(target, 'change', function(e) {
        changeCount++;
      });
    }

    function assertChanges(expectedCount) {
      assertEquals('Unexpected number of changes', expectedCount, changeCount);
    }

    function canSelectAnOptionFromASingleSelect(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      assertFalse(bot.dom.isSelected(singleSelect.options[1]));
      expectChanges(singleSelect);

      action(singleSelect.options[1]);

      assertChanges(1);
      assertTrue(bot.dom.isSelected(singleSelect.options[1]));
    }

    var testClickCanSelectAnOptionFromASingleSelect =
        goog.partial(canSelectAnOptionFromASingleSelect, bot.action.click);

    var testTapCanSelectAnOptionFromASingleSelect =
        goog.partial(canSelectAnOptionFromASingleSelect, bot.action.tap);

    function cannotDeselectAnOptionFromASingleSelect(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      assertTrue(bot.dom.isSelected(singleSelect.options[0]));
      expectChanges(singleSelect);

      action(singleSelect.options[0]);

      assertChanges(0);
      assertTrue(bot.dom.isSelected(singleSelect.options[0]));
    }

    var testClickCannotDeselectAnOptionFromASingleSelect =
        goog.partial(cannotDeselectAnOptionFromASingleSelect, bot.action.click);

    var testTapCannotDeselectAnOptionFromASingleSelect =
        goog.partial(cannotDeselectAnOptionFromASingleSelect, bot.action.tap);

    function cannotSelectAnOptionFromADisabledSelect(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      singleSelect.disabled = true;
      assertFalse(bot.dom.isSelected(singleSelect.options[1]));
      expectChanges(singleSelect);

      action(singleSelect.options[1]);

      assertChanges(0);
      assertFalse(bot.dom.isSelected(singleSelect.options[1]));
      singleSelect.disabled = false;
    }

    var testClickCannotSelectAnOptionFromADisabled =
        goog.partial(cannotSelectAnOptionFromADisabledSelect, bot.action.click);

    var testTapCannotSelectAnOptionFromADisabled =
        goog.partial(cannotSelectAnOptionFromADisabledSelect, bot.action.tap);

    function canSelectAnEnabledOptionFromASelectWithADisabledOption(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      singleSelect.options[1].disabled = true;
      assertFalse(bot.dom.isSelected(singleSelect.options[2]));
      expectChanges(singleSelect);

      action(singleSelect.options[2]);

      assertChanges(1);
      assertTrue(bot.dom.isSelected(singleSelect.options[2]));
      singleSelect.options[1].disabled = false;
    }

    var testClickCanSelectAnEnabledOptionFromASelectWithADisabledOption =
        goog.partial(canSelectAnEnabledOptionFromASelectWithADisabledOption,
                     bot.action.click);

    var testTapCanSelectAnEnabledOptionFromASelectWithADisabledOption =
        goog.partial(canSelectAnEnabledOptionFromASelectWithADisabledOption,
                     bot.action.tap);

    function canToggleOptionsInAMultiSelect(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      multiSelect.options[0].selected = true;
      expectChanges(multiSelect);

      action(multiSelect.options[0]);
      action(multiSelect.options[1]);
      action(multiSelect.options[2]);

      assertChanges(3);
      assertFalse(bot.dom.isSelected(multiSelect.options[0]));
      assertTrue(bot.dom.isSelected(multiSelect.options[1]));
      assertTrue(bot.dom.isSelected(multiSelect.options[2]));
    }

    var testClickCanToggleOptionsInAMultiSelect =
        goog.partial(canToggleOptionsInAMultiSelect, bot.action.click);

    var testTapCanToggleOptionsInAMultiSelect =
        goog.partial(canToggleOptionsInAMultiSelect, bot.action.tap);

    function canToggleCheckboxes(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      // IE fires a change event on the next click after the change.
      checkboxes[0].checked = true;
      expectChanges(checkboxes[0]);
      action(checkboxes[0]);
      assertChanges(bot.userAgent.IE_DOC_PRE9 ? 0 : 1);

      if (!goog.userAgent.IE) {
        expectChanges(checkboxes[1]);
      }
      action(checkboxes[1]);
      assertChanges(1);

      expectChanges(checkboxes[bot.userAgent.IE_DOC_PRE9 ? 1 : 2]);
      action(checkboxes[2]);
      assertChanges(1);

      assertFalse(bot.dom.isSelected(checkboxes[0]));
      assertTrue(bot.dom.isSelected(checkboxes[1]));
      assertTrue(bot.dom.isSelected(checkboxes[2]));
    }

    var testClickCanToggleCheckboxes =
        goog.partial(canToggleCheckboxes, bot.action.click);

    var testTapCanToggleCheckboxes =
        goog.partial(canToggleCheckboxes, bot.action.tap);

    function canSelectRadioButtons(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      // IE fires a change event on the next click after the change.
      expectChanges(radioButtons[0]);
      action(radioButtons[0]);
      assertChanges(bot.userAgent.IE_DOC_PRE9 ? 0 : 1);

      assertTrue(bot.dom.isSelected(radioButtons[0]));

      if (!goog.userAgent.IE) {
        expectChanges(radioButtons[1]);
      }
      action(radioButtons[1]);
      assertChanges(1);
      assertTrue(bot.dom.isSelected(radioButtons[1]));

      expectChanges(radioButtons[bot.userAgent.IE_DOC_PRE9 ? 1 : 2]);
      action(radioButtons[2]);
      assertChanges(1);
      assertTrue(bot.dom.isSelected(radioButtons[2]));
    }

    var testClickCanSelectRadioButtons =
        goog.partial(canSelectRadioButtons, bot.action.click);

    var testTapCanSelectRadioButtons =
        goog.partial(canSelectRadioButtons, bot.action.tap);

    function cannotDeselectRadioButtons(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      radioButtons[0].checked = true;
      expectChanges(radioButtons[0]);

      action(radioButtons[0]);

      assertChanges(0);
      assertTrue(bot.dom.isSelected(radioButtons[0]));
    }

    var testClickCannotDeselectRadioButtons =
        goog.partial(cannotDeselectRadioButtons, bot.action.click);

    var testTapCannotDeselectRadioButtons =
        goog.partial(cannotDeselectRadioButtons, bot.action.tap);

    function cannotSelectDisabledElements(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      function assertCannotSelectWhenDisabled(elem, isOption) {
        elem.disabled = true;
        expectChanges(isOption ? elem.parentNode : elem);

        action(elem);

        assertChanges(0);
        assertFalse(bot.dom.isSelected(elem));
        elem.disabled = false;
      }

      assertCannotSelectWhenDisabled(singleSelect.options[1], true);
      assertCannotSelectWhenDisabled(multiSelect.options[0], true);
      assertCannotSelectWhenDisabled(checkboxes[0], false);
      assertCannotSelectWhenDisabled(radioButtons[0], false);
    }

    var testClickCannotSelectDisabledElements =
        goog.partial(cannotSelectDisabledElements, bot.action.click);

    var testTapCannotSelectDisabledElements =
        goog.partial(cannotSelectDisabledElements, bot.action.tap);

    function canSelectOptionWhenDefaultPrevented(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      function assertCanSelectWhenDefaultPrevented(elem) {
        goog.events.listen(elem, 'click', function(e) {
          e.preventDefault();
        });
        expectChanges(elem.parentNode);

        action(elem);

        assertChanges(1);
        assertTrue(bot.dom.isSelected(elem));
      }

      assertCanSelectWhenDefaultPrevented(singleSelect.options[1]);
      assertCanSelectWhenDefaultPrevented(multiSelect.options[0]);
    }

    var testClickCanSelectOptionWhenDefaultPrevented =
        goog.partial(canSelectOptionWhenDefaultPrevented, bot.action.click);

    var testTapCanSelectOptionWhenDefaultPrevented =
        goog.partial(canSelectOptionWhenDefaultPrevented, bot.action.tap);

    function cannotSelectCheckboxWhenDefaultPrevented(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      var elem = checkboxes[0];
      goog.events.listen(elem, 'click', function(e) {
        e.preventDefault();
      });
      expectChanges(elem);

      action(elem);

      // WebKit and IE9 standards mode fire change events when the
      // checkbox isn't toggled.
      assertChanges(
          goog.userAgent.WEBKIT || bot.userAgent.IE_DOC_9 ? 1 : 0);
      assertFalse(bot.dom.isSelected(elem));
    }

    var testClickCannotSelectCheckboxWhenDefaultPrevented =
        goog.partial(cannotSelectCheckboxWhenDefaultPrevented,
                     bot.action.click);

    var testTapCannotSelectCheckboxWhenDefaultPrevented =
        goog.partial(cannotSelectCheckboxWhenDefaultPrevented, bot.action.tap);

    function maybeSelectRadioButtonWhenDefaultPrevented(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      var elem = radioButtons[0];
      goog.events.listen(elem, 'click', function(e) {
        e.preventDefault();
      });
      expectChanges(elem);

      action(elem);

      // WebKit and Firefox select a radio button even when the handler
      // prevents the default; IE and Opera do not.
      if (goog.userAgent.WEBKIT || goog.userAgent.GECKO) {
        // Gecko does toggle the radio button, but doesn't fire a change event.
        assertChanges(goog.userAgent.GECKO ? 0 : 1);
        assertTrue(bot.dom.isSelected(elem));
      } else {
        // IE9 standards mode still fires the change event.
        assertChanges(bot.userAgent.IE_DOC_9 ? 1 : 0);
        assertFalse(bot.dom.isSelected(elem));
      }
    }

    var testClickMaybeSelectRadioButtonWhenDefaultPrevented =
        goog.partial(maybeSelectRadioButtonWhenDefaultPrevented,
                     bot.action.click);

    var testTapMaybeSelectRadioButtonWhenDefaultPrevented =
        goog.partial(maybeSelectRadioButtonWhenDefaultPrevented,
                     bot.action.tap);

    /** @see http://code.google.com/p/selenium/issues/detail?id=1941 */
    function canSelectOptionFromTransparentSelect(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      var style = singleSelect.style;
      style['opacity'] = '0';
      style['filter'] = 'alpha(opacity=0)';
      assertEquals(0, bot.dom.getOpacity(singleSelect));
      assertFalse(bot.dom.isSelected(singleSelect.options[1]));
      expectChanges(singleSelect);

      bot.action.click(singleSelect.options[1]);

      assertChanges(1);
      assertTrue(bot.dom.isSelected(singleSelect.options[1]));
      style['opacity'] = '';
      style['filter'] = '';
      assertEquals(1, bot.dom.getOpacity(singleSelect));
    }

    var testClickCanSelectOptionFromTransparentSelect =
        goog.partial(canSelectOptionFromTransparentSelect, bot.action.click);

    var testTapCanSelectOptionFromTransparentSelect =
        goog.partial(canSelectOptionFromTransparentSelect, bot.action.tap);

    function noErrorAfterSelectWhenOnChangePreventsDefault(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      goog.events.listen(radioButtons[1], 'change', function(e) {
        e.preventDefault();
      });
      action(radioButtons[1]);
      assertTrue(bot.dom.isSelected(radioButtons[1]));

      // In IE, this second click used to throw an "Unspecified error".
      action(radioButtons[2]);
    }

    var testClickNoErrorAfterSelectWhenOnChangePreventsDefault =
        goog.partial(noErrorAfterSelectWhenOnChangePreventsDefault,
                     bot.action.click);

    var testTapNoErrorAfterSelectWhenOnChangePreventsDefault =
        goog.partial(noErrorAfterSelectWhenOnChangePreventsDefault,
                     bot.action.tap);

    function selectOptionTriggersJQueryChangeHandler(action) {
      if (!checkActionCompatibility(action)) {
        return;
      }
      var changes = 0;
      $('#singleSelect').change(function() {
        changes++;
      });

      action(singleSelect.options[1]);

      assertEquals(1, changes);
      $('#singleSelect').unbind();
    }

    var testClickSelectOptionTriggersJQueryChangeHandler =
        goog.partial(selectOptionTriggersJQueryChangeHandler, bot.action.click);

    var testTapSelectOptionTriggersJQueryChangeHandler =
        goog.partial(selectOptionTriggersJQueryChangeHandler, bot.action.tap);

  </script>
</head>
<body>
  <form action="#" method="get">
    <select id="singleSelect">
      <option id="singleOption1" value="foo">foo</option>
      <option id="singleOption2" value="bar">bar</option>
      <option id="singleOption3" value="baz">baz</option>
    </select>
    <br>
    <select id="multiSelect" multiple>
      <option id="multiOption1" value="apples">apples</option>
      <option id="multiOption2" value="oranges">oranges</option>
      <option id="multiOption3" value="cherries">cherries</option>
    </select>
    <br>
    <input type="checkbox" name="checkbox" value="peas">peas
    <input type="checkbox" name="checkbox" value="spinach">spinach
    <input type="checkbox" name="checkbox" value="broccoli">broccoli
    <br>
    <input type="radio" name="radio" value="cheese">cheese
    <input type="radio" name="radio" value="water">water
    <input type="radio" name="radio" value="bread">bread
  </form>
</body>
</html>
